﻿// WebViewManager.cs
using Microsoft.Web.WebView2.Core; 
using Microsoft.Web.WebView2.Wpf;
using System;
using System.Collections.Concurrent;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using WebViewControl.Contracts;

namespace WebViewModule.Services
{
    public class DefaultEnvironmentProvider : IWebViewEnvironmentProvider
    {
        private CoreWebView2Environment _cachedEnvironment;
        private readonly string _dataFolder;
        public DefaultEnvironmentProvider()
        {
            // 使用程序执行目录下的 WebViewData 文件夹
            _dataFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "WebViewData");
            Directory.CreateDirectory(_dataFolder);
        }

        public async Task<CoreWebView2Environment> GetEnvironmentAsync()
        {
            if (_cachedEnvironment != null)
                return _cachedEnvironment;

            _cachedEnvironment = await CoreWebView2Environment.CreateAsync(null, _dataFolder);
            return _cachedEnvironment;
        }
        public async Task<CoreWebView2Environment> GetEnvironmentAsync(string userDataFolder, string browserExecutableFolder)
        {
            if (_cachedEnvironment != null)
                return _cachedEnvironment;

            _cachedEnvironment = await CoreWebView2Environment.CreateAsync(browserExecutableFolder, userDataFolder);
            return _cachedEnvironment;
        }

        public Task<CoreWebView2Environment> CreateEnvironmentAsync(string userDataFolder, string browserExecutableFolder)
        {
            throw new NotImplementedException();
        }
    }

    public class WebViewManager : IWebViewManager, IDisposable
    {
        public event EventHandler<string> WebViewInitialized;
        private readonly IWebViewEnvironmentProvider _envProvider;
        private readonly ConcurrentDictionary<string, WebView2> _instances = new();
        private readonly SemaphoreSlim _semaphore = new(1, 1);
        private readonly Timer _cleanupTimer;
        private readonly TimeSpan _maxIdleTime = TimeSpan.FromMinutes(10);
        private readonly ConcurrentDictionary<string, DateTime> _lastUsed = new();
        private readonly int _maxPoolSize = 10;

        public WebViewManager(IWebViewEnvironmentProvider envProvider)
        {
            _envProvider = envProvider;
            _cleanupTimer = new Timer(CleanupCallback, null, TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(5));
        }

        public async Task<WebView2> CreateOrGetAsync(string key, string userDataFolder = null)
        {
            if (_instances.TryGetValue(key, out var existing))
            {
                _lastUsed[key] = DateTime.UtcNow;
                return existing;
            }

            await _semaphore.WaitAsync();
            try
            {
                if (_instances.ContainsKey(key))
                    return _instances[key];

                if (_instances.Count >= _maxPoolSize)
                    throw new InvalidOperationException("WebView2 instance pool has reached its limit.");

                var webView = new WebView2();
                 var env = await _envProvider.GetEnvironmentAsync();

                if (!string.IsNullOrEmpty(userDataFolder))
                {
                    Directory.CreateDirectory(userDataFolder);
                    env = await CoreWebView2Environment.CreateAsync(null, userDataFolder);
                } 
                _instances[key] = webView;
                _lastUsed[key] = DateTime.UtcNow;
                return webView;
            }
            catch(Exception e)
            {
                return  null;
            }
            finally
            {
                _semaphore.Release();
            }
        }
        public async Task InitializeAsync(string key)
        {
            if (!_instances.TryGetValue(key, out var webView))
                throw new InvalidOperationException("WebView not found");

            if (webView.CoreWebView2 != null)
                return;

            try
            {
                var env = await _envProvider.GetEnvironmentAsync();

                await Application.Current.Dispatcher.InvokeAsync(async () =>
                {
                    await webView.EnsureCoreWebView2Async(env);
                    ConfigureSettings(webView);

                    // ✅ 初始化成功后触发事件
                    WebViewInitialized?.Invoke(this, key);
                });
            }
            catch (Exception ex)
            {
                // 可选：记录错误
            }
        }
        public WebView2 Get(string key)
        {
            return _instances.TryGetValue(key, out var view) ? view : null;
        }

        public async Task NavigateAsync(string key, string url)
        {
            var instance = await CreateOrGetAsync(key);
            if (instance.CoreWebView2 == null) return;

            if (File.Exists(url) && !url.StartsWith("http", StringComparison.OrdinalIgnoreCase))
            {
                url = $"file:///{url.Replace('\\', '/')}";
            }

            await Application.Current.Dispatcher.InvokeAsync(() => { 
                instance.Source = new Uri(url);
                ConfigureSettings(instance);
            });
            _lastUsed[key] = DateTime.UtcNow;
        }

        public void SetEventHandlers(string key,
            EventHandler<CoreWebView2NavigationStartingEventArgs> navigationStarting = null,
            EventHandler<CoreWebView2NavigationCompletedEventArgs> navigationCompleted = null)
        {
            if (!_instances.TryGetValue(key, out var webView)) return;

            if (webView.CoreWebView2 == null)
            {
                webView.CoreWebView2InitializationCompleted += (s, e) =>
                {
                    if (e.IsSuccess && webView.CoreWebView2 != null)
                        AttachHandlers(webView, navigationStarting, navigationCompleted);
                };
            }
            else
            {
                AttachHandlers(webView, navigationStarting, navigationCompleted);
            }
        }

        private void AttachHandlers(WebView2 webView,
            EventHandler<CoreWebView2NavigationStartingEventArgs> navigationStarting,
            EventHandler<CoreWebView2NavigationCompletedEventArgs> navigationCompleted)
        {
            if (navigationStarting != null)
                webView.CoreWebView2.NavigationStarting += navigationStarting;
            if (navigationCompleted != null)
                webView.CoreWebView2.NavigationCompleted += navigationCompleted;
        }

        public void Release(string key)
        {
            if (_instances.TryRemove(key, out var view))
            {
                _lastUsed.TryRemove(key, out _);
                Application.Current.Dispatcher.Invoke(() =>
                {
                    if (view.Parent is Panel parent)
                        parent.Children.Remove(view);
                    view.Dispose();
                });
            }
        }

        public void ReleaseAll()
        {
            foreach (var key in _instances.Keys.ToList())
            {
                Release(key);
            }
        }

        private static void ConfigureSettings(WebView2 view)
        {
            var s = view.CoreWebView2.Settings;
            
            s.AreDevToolsEnabled = true; 
            s.AreDefaultContextMenusEnabled = true;
            s.IsZoomControlEnabled = true;
            s.IsBuiltInErrorPageEnabled = true; 
            view.HorizontalAlignment = HorizontalAlignment.Stretch;
            view.VerticalAlignment = VerticalAlignment.Stretch;
            // 设置缩放因子
            view.ZoomFactor = 1.2;
            //view.ZoomFactor = 0.80;

            // 禁用用户缩放控制
            view.CoreWebView2.Settings.IsZoomControlEnabled = false;

            // 禁用浏览器快捷键（如Ctrl+滚轮缩放）
            view.CoreWebView2.Settings.AreBrowserAcceleratorKeysEnabled = false;
            // 禁用浏览器缩放快捷键
            view.CoreWebView2.Settings.AreDefaultScriptDialogsEnabled = false;
            view.CoreWebView2.Settings.AreDevToolsEnabled = false;
            
        }

        private void CleanupCallback(object state)
        {
            var now = DateTime.UtcNow;
            foreach (var kvp in _lastUsed.ToArray())
            {
                if (now - kvp.Value > _maxIdleTime)
                {
                    Release(kvp.Key);
                }
            }
        }

        public void Dispose()
        {
            _cleanupTimer.Dispose();
            ReleaseAll();
            _semaphore.Dispose();
        }
    }
}
